package org.ala.linshen.dp;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * 给你一个 n x n 的网格 grid ，代表一块樱桃地，每个格子由以下三种数字的一种来表示：
 *
 * 0 表示这个格子是空的，所以你可以穿过它。
 * 1 表示这个格子里装着一个樱桃，你可以摘到樱桃然后穿过它。
 * -1 表示这个格子里有荆棘，挡着你的路。
 * 请你统计并返回：在遵守下列规则的情况下，能摘到的最多樱桃数：
 *
 * 从位置 (0, 0) 出发，最后到达 (n - 1, n - 1) ，只能向下或向右走，并且只能穿越有效的格子（即只可以穿过值为 0 或者 1 的格子）；
 * 当到达 (n - 1, n - 1) 后，你要继续走，直到返回到 (0, 0) ，只能向上或向左走，并且只能穿越有效的格子；
 * 当你经过一个格子且这个格子包含一个樱桃时，你将摘到樱桃并且这个格子会变成空的（值变为 0 ）；
 * 如果在 (0, 0) 和 (n - 1, n - 1) 之间不存在一条可经过的路径，则无法摘到任何一个樱桃。
 *
 *
 * 示例 1：
 *
 *
 * 输入：grid = [[0,1,-1],[1,0,-1],[1,1,1]]
 * 输出：5
 * 解释：玩家从 (0, 0) 出发：向下、向下、向右、向右移动至 (2, 2) 。
 * 在这一次行程中捡到 4 个樱桃，矩阵变成 [[0,1,-1],[0,0,-1],[0,0,0]] 。
 * 然后，玩家向左、向上、向上、向左返回起点，再捡到 1 个樱桃。
 * 总共捡到 5 个樱桃，这是最大可能值。
 * 示例 2：
 *
 * 输入：grid = [[1,1,-1],[1,-1,1],[-1,1,1]]
 * 输出：0
 *
 *
 * 提示：
 *
 * n == grid.length
 * n == grid[i].length
 * 1 <= n <= 50
 * grid[i][j] 为 -1、0 或 1
 * grid[0][0] != -1
 * grid[n - 1][n - 1] != -1
 *
 * @author ala
 * @date 2024-09-26 13:27
 */
public class Q741 {

    public static void main(String[] args) {
        Q741 q = new Q741();

        int[][] grid = {{0,1,-1},{1,0,-1},{1,1,1}};
//        int[][] grid = {
//                { 1, 1,-1},
//                { 1,-1, 1},
//                {-1, 1, 1}};
//        int[][] grid = {
//                {1,1,1,1,0,0,0},
//                {0,0,0,1,0,0,0},
//                {0,0,0,1,0,0,1},
//                {1,0,0,1,0,0,0},
//                {0,0,0,1,0,0,0},
//                {0,0,0,1,0,0,0},
//                {0,0,0,1,1,1,1}};

        System.out.println(q.cherryPickup(grid));
    }

    public int cherryPickup(int[][] grid) {
        if (grid[0][0] == -1) {return 0;}
        M = grid.length; N = grid[0].length;
        int r = V1(grid);
        return r < 0 ? 0 : r;
    }
    static int INF = -10000;
    int M, N;
    /**
     *  1）两个人都站在(0,0)处，回收樱桃，走到(M-1, N-1)处时统计两个人回收的最多樱桃
     *  2）dfs(t, j1, j2)：表示走了 t 步，第一个人走到(t-j1, j1)，第二个人走到(t-j2, j2)处时的最大回收数量
     *      dfs(t, j1, j2) = max(
     *                          dfs(t-1,   j,   j2)     1 从上到下，2 从上到下
     *                          dfs(t-1, j-1,   j2)     1 从左往右，2 从上到下
     *                          dfs(t-1,   j, j2-1)     1 从上到下，2 从左往右
     *                          dfs(t-1, j-1, j2-1)     1 从左往右，2 从左往右
     *                      )
     *                          +
     *                      1 和 2 走到同一点上：grid[t - j1][j1]
     *                      1 和 2 走到不同点上：grid[t - j1][j1] + grid[t - j2][j2]
     *  3）整个过程记忆搜，递归入口是dfs(M + N - 1, N - 1, N - 1)
     */
    protected int V1(int[][] grid) {
        this.grid = grid;
        memo = new int[M + N][N][N];
        for (int t = 0 ; t < M + N ; t++) {
            for (int i = 0 ; i < N ; i++) {
                Arrays.fill(memo[t][i], -1);
            }
        }
        return dfs(M + N - 2, N - 1, N - 1);
    }
    protected int[][] grid;
    protected int[][][] memo;
    protected int dfs(int t, int j1, int j2) {
        if (t == 0) {return grid[0][0];}
        int i1 = t - j1, i2 = t - j2;
        if (i1 < 0 || i1 == M || j1 < 0 || j1 == N || i2 < 0 || i2 == M || j2 < 0 || j2 == N) {
            return INF;
        }

        int res = memo[t][j1][j2];
        if (res != -1) {return res;}

        int v1 = grid[i1][j1] == -1 ? INF : grid[i1][j1],
            v2 = grid[i2][j2] == -1 ? INF : grid[i2][j2];
        if (i1 == i2 && j1 == j2 && v2 > 0) {
            v2 = 0;
        }

        int uu = dfs(t - 1, j1, j2),
            lu = dfs(t - 1, j1 - 1, j2),
            ul = dfs(t - 1, j1, j2 - 1),
            ll = dfs(t - 1, j1 - 1, j2 - 1);
        res = Math.max(Math.max(uu, ul), Math.max(lu, ll)) + v1 + v2;

        return memo[t][j1][j2] = res;
    }



}
